package vn.bang.xiangqi.server;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Queue;

import vn.bang.communication.Command;
import vn.bang.communication.Communicator;
import vn.bang.entity.GameDTO;
import vn.bang.entity.PlayerDTO;
import vn.bang.xiangqi.server.thread.BaseThread;
import vn.bang.xiangqi.server.thread.IProcess;

public abstract class AbstractBaseServer implements IServer {
	
	static public final Integer STOP_STATUS = 0;
	static public final Integer START_STATUS = 1;
	
	private IProcess iProcess = new IProcess() {
		
		public void process() {
			start();
		}
	};
	
	protected Collection<BaseThread> threads = new ArrayList<BaseThread>();
	protected Queue<Command> commandQueue;
	protected Collection<PlayerDTO> players;
	protected Collection<GameDTO> games;
	protected Map<Long, Communicator> communicators;
	private int numberOfThreads;
	private Integer status = STOP_STATUS;
	
	public int getNumberOfThreads() {
		return numberOfThreads;
	}
	
	abstract protected void start();
	abstract protected void stop();
	
	protected AbstractBaseServer(Queue<Command> commandQueue, Map<Long, Communicator> communicators, Collection<PlayerDTO> players, Collection<GameDTO> games, int numberOfThreads) {
		this.commandQueue = commandQueue;
		this.communicators = communicators;
		this.players = players;
		this.games = games;
		this.numberOfThreads = numberOfThreads;
		this.addNewServerThread(threads, iProcess, numberOfThreads);
	}
	
	@Override
	public void startup() {
		setStatus(START_STATUS);
		startAllThreads(threads);
	}
	
	@Override
	public void shutdown() {
		stop();
		closeResources(threads);
		setStatus(STOP_STATUS);
	}
	
	@Override
	public Integer getStatus() {
		return status;
	}
	
	protected void addCommandToQueue(Command command) {
		commandQueue.add(command);
	}
	
	protected void addPlayer(PlayerDTO player) {
		players.add(player);
	}
	
	protected void addCommunicator(Long playerId, Communicator communicator) {
		communicators.put(playerId, communicator);
	}

	private void setStatus(Integer state) {
		status = state;
	}
	
	private void closeResources(Collection<BaseThread> baseThreads) {
		killAllThreads(baseThreads);
	}

	private void killAllThreads(Collection<BaseThread> baseThreads) {
		for (BaseThread baseThread : baseThreads) {
			killThread(baseThread);
		}
	}

	private void killThread(BaseThread baseThread) {
		baseThread.shutdown();
	}
	
	private void addNewServerThread(Collection<BaseThread> baseThreads, IProcess process, int numberOfThreads) {
		for (int i = 0; i < numberOfThreads; i++) {
			addNewServerThread(baseThreads, process);
		}
	}
	
	private void addNewServerThread(Collection<BaseThread> baseThreads, IProcess process) {
		BaseThread baseThread = new BaseThread();
		baseThread.setProcessor(process);
		baseThreads.add(baseThread);
	}
	
	private void startAllThreads(Collection<BaseThread> baseThreads) {
		if (null != baseThreads && !baseThreads.isEmpty()) {
			for (BaseThread baseThread : baseThreads) {
				baseThread.start();
			}
		}
	}
	
}
